import * as React from 'react';
import classNames from 'classnames';

// 删除需要删除的对象的属性å
import omit from 'rc-util/lib/omit';
import { Omit, tuple } from '../_util/type';

import SizeContext, { SizeType } from '../config-provider/SizeContext';

// 判断是否没有边框的按钮
function isUnborderedButtonType(type: ButtonType | undefined) {
    return type === 'text' || type === 'link';
}

// 当传入的是children时
function spaceChildren(children: React.ReactNode) {
    let isPrevChildPure: boolean = false;
    const childList: React.ReactNode[] = [];
    React.Children.forEach(children, child => {
        const type = typeof child;
        const isCurrentChildPure = type === 'string' || type === 'number';
        if (isPrevChildPure && isCurrentChildPure) {
            const lastIndex = childList.length - 1;
            const lastChild = childList[lastIndex];
            childList[lastIndex] = `${lastChild}${child}`;
        } else {
            childList.push(child);
        }

        isPrevChildPure = isCurrentChildPure;
    });

    return React.Children.map(childList, child => child);
}

const ButtonTypes = tuple('default', 'primary', 'ghost', 'dashed', 'link', 'text');
export type ButtonType = typeof ButtonTypes[number];

const ButtonShapes = tuple('circle', 'round');
export type ButtonShape = typeof ButtonShapes[number];

const ButtonHTMLTypes = tuple('submit', 'button', 'reset');
export type ButtonHTMLType = typeof ButtonHTMLTypes[number];

export type LegacyButtonType = ButtonType | 'danger';
export function converLegacyProps(type?: LegacyButtonType): ButtonProps {
    if (type === 'danger') {
        return { danger: true }
    }

    return { type };
};

export interface BaseButtonProps {
    type?: ButtonType;
    icon?: React.ReactNode;
    shape?: ButtonShape;
    size?: SizeType;
    loading?: boolean | { delay?: number };
    prefixCls?: string;
    className?: string;
    ghost?: boolean;
    danger?: boolean;
    block?: boolean;
    children?: React.ReactNode;
};

export type AnchorButtonProps = {
    href?: string;
    target?: string;
    onClick?: React.MouseEventHandler<HTMLElement>;
} &
    BaseButtonProps &
    Omit<React.AnchorHTMLAttributes<any>, 'type' | 'onClick'>;

export type NativeButtonProps = {
    htmlType?: ButtonHTMLType;
    onClick?: React.MouseEventHandler<HTMLElement>;
} &
    BaseButtonProps &
    Omit<React.ButtonHTMLAttributes<any>, 'type' | 'onClick'>;

export type ButtonProps = Partial<AnchorButtonProps & NativeButtonProps>;

interface CompoundedComponent extends
    React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLElement>> {
};

type Loading = number | boolean;

const InternalButton: React.ForwardRefRenderFunction<unknown, ButtonProps> = (props, ref) => {
    const {
        loading = false,
        // prefixCls: ,
        type,
        danger,
        shape,
        size: customizeSize,
        className,
        children,
        icon,
        ghost = false,
        block = false,
        htmlType = 'button' as ButtonProps['htmlType'],
        ...rest
    } = props;

    const size = React.useContext(SizeContext);
    const [innerLoading, setLoading] = React.useState<Loading>(!!loading);
    const buttonRef = (ref as any) || React.createRef<HTMLElement>();
    const delayTimeoutRef = React.useRef<number>();

    let loadingOrDelay: Loading;
    if (typeof loading === 'object' && loading.delay) {
        loadingOrDelay = loading.delay || true;
    } else {
        loadingOrDelay = !!loading;
    }

    React.useEffect(() => {
        clearTimeout(delayTimeoutRef.current);

        if (typeof loadingOrDelay === 'number') {
            delayTimeoutRef.current = window.setTimeout(() => {
                setLoading(loadingOrDelay);
            }, loadingOrDelay)
        } else {
            setLoading(loadingOrDelay)
        }
    }, [loadingOrDelay]);

    const handleClick = (e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement, MouseEvent>) => {
        const { onClick } = props;
        if (innerLoading) return;

        (onClick as React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>)?.(e);
    }

    let sizeCls = '';
    switch (customizeSize || size) {
        case 'large':
            sizeCls = 'lg';
            break;
        case 'small':
            sizeCls = 'sm';
            break;
        default:
            break;
    }

    const iconType = innerLoading ? 'loading' : icon;

    const classes = classNames('btn', {
        [`btn-${type}`]: type,
        [`btn-${shape}`]: shape,
        [`btn-${sizeCls}`]: sizeCls,
        [`btn-icon-only`]: !children && children !== 0 && iconType,
        [`btn-background-ghost`]: ghost && !isUnborderedButtonType(type),
        [`btn-loading`]: innerLoading,
        [`btn-block`]: block,
        [`btn-danger`]: !!danger,
    }, className);

    const kids =
        children || children === 0
            ? spaceChildren(children)
            : null;

    const linkButtonRestProps = omit(rest as AnchorButtonProps & { navigate: any }, ['navigate']);
    if (linkButtonRestProps.href !== undefined) {
        return (
            <a
                {...linkButtonRestProps}
                className={classes}
                onClick={handleClick}
                ref={buttonRef}>
                {kids}
            </a>
        );
    }

    const buttonNode = (
        <button
            {...(rest as NativeButtonProps)}
            type={htmlType}
            className={classes}
            onClick={handleClick}
            ref={buttonRef}
        >
            {kids}
        </button>
    );

    return buttonNode;
};

const Button = React.forwardRef<unknown, ButtonProps>(InternalButton) as CompoundedComponent;

Button.displayName = 'Button';

export default Button;